package com.nx.biz.shopify.service;

import cn.hutool.json.JSONUtil;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.nx.biz.shopify.api.RedisKeys;
import com.nx.biz.shopify.api.bo.ShopifyFulfillment;
import com.nx.biz.shopify.api.bo.ShopifyOrder;
import com.nx.biz.shopify.api.bo.ShopifySession;
import com.nx.biz.shopify.convert.ShopifyFulfillmentConverter;
import com.nx.biz.shopify.convert.ShopifyOrderConverter;
import com.nx.biz.shopify.repo.ShopifyFulfillmentRepository;
import com.nx.biz.shopify.repo.ShopifyOrderRepository;
import com.nx.biz.shopify.sdk.ShopifySdk.FulfillmentOrderSdk;
import com.nx.biz.shopify.sdk.ShopifySdk.model.bo.FulfillmentBo;
import com.nx.biz.shopify.sdk.ShopifySdk.model.bo.FulfillmentOrderBo;
import com.nx.biz.shopify.sdk.ShopifySdk.model.bo.OrderBoV2;
import com.nx.biz.shopify.sdk.ShopifySdk.model.constant.FulfillmentEventStatusConstants;
import com.nx.biz.shopify.support.ShopifyContext;
import com.nx.common.tools.CheckTools;
import com.nx.common.tools.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ShopifyWebhookService {

    private static final Gson GSON = new Gson();

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private ShopifyOrderConverter shopifyOrderConverter;
    @Resource
    private ShopifyFulfillmentConverter shopifyFulfillmentConverter;

    @Resource
    private ShopifyOrderRepository shopifyOrderRepository;
    @Resource
    private ShopifyFulfillmentRepository shopifyFulfillmentRepository;

    @Resource
    private FulfillmentOrderSdk fulfillmentOrderSdk;

    @Resource
    private ShopifyContext shopifyContext;

    /**
     * 响应shopify订单创建事件
     */
    @Transactional(rollbackFor = Exception.class)
    public void onOrderCreate(String payload, String shopDomain) throws IOException {
        log.info("onOrderCreate, payload : {}", payload);

        /** 1. 解析 */
        OrderBoV2 orderBo = GSON.fromJson(payload, OrderBoV2.class);
        log.info("onOrderCreate, 参数格式化后: {}", orderBo);

        /** 2. 查询是否重复 */
        Object redisPayload = redisUtil.hget(RedisKeys.shopifyOrder, String.valueOf(orderBo.getId()));
        if (CheckTools.isNotNullOrEmpty(redisPayload)) {
            log.warn("订单 [{}]已存在, 不需要重复处理", orderBo.getId());
            return;
        }

        /** 3. 参数转换&存储db */
        // redis 缓存
        redisUtil.hset(RedisKeys.shopifyOrder, String.valueOf(orderBo.getId()), payload);
        // 参数转换
        ShopifyOrder shopifyOrder = shopifyOrderConverter.orderBo2OrderEo(null, orderBo);
        shopifyOrder.setShopDomain(shopDomain);

        // db落库
        String dbId = shopifyOrderRepository.save(shopifyOrder);
        log.info("onOrderCreate, 处理完成。落库后，id: [{}] - [{}]", dbId, shopifyOrder.getId());
    }

    /**
     * 响应shopify订单更新事件
     */
    @Transactional(rollbackFor = Exception.class)
    public void onOrderUpdate(String payload, String shopDomain) throws IOException {
        log.info("onOrderUpdate, payload : {}", payload);

        /** 1. 解析 */
        OrderBoV2 orderBo = GSON.fromJson(payload, OrderBoV2.class);
        log.info("onOrderUpdate, 参数格式化后: {}", orderBo);

        /** 2. 查询是否存在, 如果不存在，走新建流程 */
        Object redisPayload = redisUtil.hget(RedisKeys.shopifyOrder, String.valueOf(orderBo.getId()));
        if (CheckTools.isNullOrEmpty(redisPayload)) {
            onOrderCreate(payload, shopDomain);
        }

        /** 3. 参数转换&存储db */
        // redis 缓存
        redisUtil.hset(RedisKeys.shopifyOrder, String.valueOf(orderBo.getId()), payload);
        // 参数转换
        ShopifyOrder shopifyOrderBo = shopifyOrderRepository.queryById(String.valueOf(orderBo.getId()));
        ShopifyOrder shopifyOrderBoLast = shopifyOrderConverter.orderBo2OrderEo(shopifyOrderBo, orderBo);
        shopifyOrderBoLast.setShopDomain(shopDomain);

        // db落库
        shopifyOrderRepository.update(shopifyOrderBoLast);
        log.info("onOrderUpdate 处理完成, 落库后，id: [{}]", shopifyOrderBoLast.getId());
    }

    /**
     * 响应shopify订单删除事件
     */
    @Transactional(rollbackFor = Exception.class)
    public void onOrderDelete(String payload, String shopDomain) throws IOException {
        log.info("onOrderDelete, payload : {}", payload);

        /** 1. 解析 */
        JsonElement jsonElement = new JsonParser().parse(payload).getAsJsonObject().get("id");
        Long orderId = jsonElement.getAsLong();

        /** 2. 从redis 删除 */
        Object redisPayload = redisUtil.hget(RedisKeys.shopifyOrder, String.valueOf(orderId));
        if (CheckTools.isNotNullOrEmpty(redisPayload)) {
            redisUtil.hdel("shopify_order", String.valueOf(orderId));
        }

        /** 3. 从db 删除*/
        shopifyOrderRepository.deleteById(String.valueOf(orderId));
    }

    /**
     * 响应shopify订单付款事件
     */
    @Transactional(rollbackFor = Exception.class)
    public void onOrderPaid(String payload, String shopDomain) throws IOException {
        log.info("onOrderPaid, payload : {}，shopDomain : {}", payload, shopDomain);
        onOrderUpdate(payload, shopDomain);
    }

    /**
     * 响应shopify订单履约事件
     */
    @Transactional(rollbackFor = Exception.class)
    public void onOrderFulfill(String payload, String shopDomain) throws IOException {
        log.info("onOrderFulfill, payload : {}，shopDomain : {}", payload, shopDomain);
        onOrderUpdate(payload, shopDomain);
    }

    /**
     * 响应shopify履约单创建事件
     */
    @Transactional(rollbackFor = Exception.class)
    public void onFulfillmentCreate(String payload, String shopDomain) throws IOException {
        /** 1. 解析 */
        FulfillmentBo fulfillmentBo = null;
        try {
            String jsonStr = JSONUtil.toJsonStr(payload);
            fulfillmentBo = JSONUtil.toBean(jsonStr, FulfillmentBo.class);
        } catch (Exception e) {
            fulfillmentBo = GSON.fromJson(GSON.toJson(payload), FulfillmentBo.class);
        }
        log.info("onFulfillmentCreate, 收单参数格式化后: {}", fulfillmentBo);

        /** 2. 查询是否重复 */
        Object redisPayload = redisUtil.hget(RedisKeys.shopifyFulfillment, String.valueOf(fulfillmentBo.getId()));
        if (CheckTools.isNotNullOrEmpty(redisPayload)) {
            log.warn("fulfillment [{}]已存在, 不需要重复处理", fulfillmentBo.getId());
            return;
        }

        /** 3. 向shopify查询fulfillment order */
        ShopifySession matchSession = shopifyContext.getMatchSession(shopDomain);
        if (CheckTools.isNullOrEmpty(matchSession)) {
            log.error("Fulfillment创建失败，获取shop：{}的会话失败", shopDomain);
            return;
        }
        List<FulfillmentOrderBo> fulfillmentOrderBoList = fulfillmentOrderSdk.listAssignFulfillmentOrderByOrderId(
                fulfillmentBo.getOrder_id(),
                matchSession.getShop(),
                shopifyContext.getApiVersion(),
                matchSession.getAccessToken()
        );
        List<FulfillmentOrderBo> fulfillmentOrderBoFilteredList = fulfillmentOrderBoList.stream()
                .filter(item -> !item.getStatus().equals(FulfillmentEventStatusConstants.cancelled)).collect(Collectors.toList());
        if (CheckTools.isNullOrEmpty(fulfillmentOrderBoFilteredList)) {
            log.warn("未找到fulfillment order，orderId:[{}]", fulfillmentBo.getOrder_id());
            return;
        }
        FulfillmentOrderBo fulfillmentOrderBo = fulfillmentOrderBoFilteredList.get(0);
        log.info("onFulfillmentCreate, 从shopify 查询的 fulfillmentOrderBo: {}", fulfillmentOrderBo);

        /** 4. 存储fulfillment对象 */
        // 4.1.存储fulfillment到redis
        redisUtil.hset(RedisKeys.shopifyFulfillment, String.valueOf(fulfillmentBo.getId()), GSON.toJson(fulfillmentBo));
        redisPayload = redisUtil.hget(RedisKeys.shopifyFulfillment, String.valueOf(fulfillmentBo.getId()));
        log.info("redis write fulfillment value: {}", redisPayload);

        // 4.2.存储fulfillment到db
        ShopifyFulfillment shopifyFulfillmentBo = shopifyFulfillmentConverter.fulfillmentBo2FulfillmentEo(null, fulfillmentBo);
        shopifyFulfillmentBo.setShopId(String.valueOf(fulfillmentOrderBo.getShopId()));
        shopifyFulfillmentBo.setFulfillmentOrderId(String.valueOf(fulfillmentOrderBo.getId()));
        shopifyFulfillmentBo.setTransferNo(null);
        shopifyFulfillmentBo.setSyncFlag(0);
        shopifyFulfillmentBo.setShopDomain(shopDomain);
        shopifyFulfillmentRepository.save(shopifyFulfillmentBo);

        /* 5、更新订单信息 */
        ShopifyOrder shopifyOrder = shopifyOrderRepository.queryById(shopifyFulfillmentBo.getOrderId());
        if (CheckTools.isNotNullOrEmpty(shopifyOrder)) {
            shopifyOrder.setTrackNumber(shopifyFulfillmentBo.getTrackingNumber());
            shopifyOrderRepository.update(shopifyOrder);
        }
    }

    /**
     * 响应shopify履约请求创建事件
     * todo 暂时无用
     */
    @Transactional(rollbackFor = Exception.class)
    public void onFulfillmentRequestCreate(String payload, String shopDomain) {
        log.info("onFulfillmentRequestCreate, payload : {}, shopDomain : {}", payload, shopDomain);
    }

}
